﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Web;
using System.Web.Caching;
using DDay.iCal;

namespace MyGroups.Model
{

    public class CalendarReader : ICalendarReader
    {

        public CalendarEventCollection GetCalendarEvents(string feedUrl)
        {
            Cache cache = HttpRuntime.Cache;
            string cacheKey = "GetCalendarEvents-" + feedUrl;
            if (Configuration.CachingEnabled)
            {
                if (cache[cacheKey] != null)
                {
                    return cache[cacheKey] as CalendarEventCollection;
                }
            }

            var collection = new CalendarEventCollection();

            try
            {
                var uri = new Uri(feedUrl);
                var calendarString = LoadFromUri(uri);
                var calendar = LoadFromString(calendarString);
                foreach (var item in calendar.Events.ToArray())
                {
                    var ce = new CalendarEvent()
                    {
                        Summary = item.Summary.Value,
                        StartDate = item.DTStart.Local,
                        EndDate = item.DTEnd.Local
                    };

                    if (item.UID != null)
                    {
                        ce.UID = item.UID.Value;
                    }
                    if (item.Description != null)
                    {
                        ce.Description = item.Description.Value;
                    }
                    else
                    {
                        ce.Description = String.Empty;
                    }
                    if (item.Location != null)
                    {
                        ce.Location = item.Location.Value;
                    }
                    else
                    {
                        ce.Location = String.Empty;
                    }
                    // only add dates after yesterday
                    if (ce.StartDate > DateTime.Now.AddDays(-1))
                    {
                        collection.Add(ce);
                    }
                }
            }
            catch (Exception ex)
            {
                // do nothing
            }

            if (Configuration.CachingEnabled)
            {
                // hold up to 5 minutes
                cache.Insert(cacheKey, collection, null, DateTime.Now.AddMinutes(5),
                    Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
            }

            // sort and limit results
            var items = collection.OrderBy(e => e.StartDate).Take(3);
            collection = new CalendarEventCollection(items);

            return collection;
        }

        #region "  Private Methods  "

        static public string LoadFromUri(Uri uri)
        {
            return LoadFromUri(typeof(iCalendar), uri, null, null, null);
        }

        static public string LoadFromUri(Uri uri, WebProxy proxy)
        {
            return LoadFromUri(typeof(iCalendar), uri, null, null, proxy);
        }

        static public string LoadFromUri(Type iCalendarType, Uri uri)
        {
            return LoadFromUri(iCalendarType, uri, null, null, null);
        }

        static public string LoadFromUri(Uri uri, string username, string password, WebProxy proxy)
        {
            return LoadFromUri(typeof(iCalendar), uri, username, password, proxy);
        }

        static public string LoadFromUri(Type iCalendarType, Uri uri, string username, string password, WebProxy proxy)
        {
            try
            {
                WebRequest request = WebRequest.Create(uri);

                if (username != null && password != null)
                {
                    request.Credentials = new System.Net.NetworkCredential(username, password);
                }

                if (proxy != null)
                {
                    request.Proxy = proxy;
                }

                AutoResetEvent evt = new AutoResetEvent(false);

                string str = null;
                request.BeginGetResponse(new AsyncCallback(
                    delegate(IAsyncResult result)
                    {
                        Encoding e = Encoding.UTF8;
                        try
                        {
                            using (WebResponse resp = request.EndGetResponse(result))
                            {
                                // Try to determine the content encoding
                                try
                                {
                                    List<string> keys = new List<string>(resp.Headers.AllKeys);
                                    if (keys.Contains("Content-Encoding"))
                                        e = Encoding.GetEncoding(resp.Headers["Content-Encoding"]);
                                }
                                catch
                                {
                                    // Fail gracefully back to UTF-8
                                }

                                using (Stream stream = resp.GetResponseStream())
                                {
                                    using (StreamReader sr = new StreamReader(stream, e))
                                    {
                                        str = sr.ReadToEnd();
                                    }
                                }
                            }
                        }
                        finally
                        {
                            evt.Set();
                        }
                    }
                ), null);

                evt.WaitOne();

                if (str != null)
                {
                    return str;
                    //return LoadFromStream(new StringReader(str));
                }
                return null;
            }
            catch (System.Net.WebException ex)
            {
                // do nothing
                throw ex;
            }
        }

        private static iCalendar LoadFromString(string str)
        {
            return iCalendar.LoadFromStream(new StringReader(str));
        }

        
        #endregion

    }

}
